package com.killer.edu.oauth.config;

import com.killer.edu.oauth.mult.MultAuthenticationFilter;
import com.killer.edu.oauth.oauth2.enhancer.CustomTokenEnhancer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 当前类为Oauth2 server的配置类(需要继承特定的父类AuthorizationServerConfigurerAdapter)
 */
@Configuration
@EnableAuthorizationServer //开启认证服务器功能
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private MultAuthenticationFilter multAuthenticationFilter;

    /**
     * jwt 对称加密密钥
     */
    @Value("${spring.security.oauth2.jwt.signingKey}")
    private String signingKey;

    /**
     * 用来配置令牌端点的安全约束
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                //  开启端口/oauth/token_key的访问权限(允许)
                .tokenKeyAccess("permitAll()")
                //  开启端口/oauth/check_token的访问权限(允许)
                .checkTokenAccess("permitAll()")
                //  允许客户端表单认证
                .allowFormAuthenticationForClients()
                //添加授权认证过滤器
                .addTokenEndpointAuthenticationFilter(multAuthenticationFilter);
    }

    /**
     * 用来配置客户端详情服务(ClientDetailService),客户端详情信息在这里进行初始化,
     * 你能够把客户端详情信息写死在这里或者通过数据库来存储调取详情信息
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //配置客户端信息,从数据库中读取,对应oauth_client_details表
        clients.jdbc(dataSource);
    }

    /**
     * 用来配置令牌(token)的访问端点和令牌服务(token services)
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //配置token的数据源,自定义tokenService等信息,配置身份认证器,配置认证方式
        //TokenStore,TokenGranter,OAuth2RequestFactory
        endpoints.tokenStore(tokenStore())
                //该字段设置refresh token是否重复使用
                .reuseRefreshTokens(false)
                .authorizationCodeServices(authorizationCodeServices())
                .approvalStore(approvalStore())
                .tokenEnhancer(tokenEnhancerChain())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .tokenGranter(tokenGranter(endpoints));
    }

    /**
     * 授权信息持久化实现
     * @return
     */
    @Bean
    public ApprovalStore approvalStore(){
        return new JdbcApprovalStore(dataSource);
    }

    /**
     * 授权码模式持久化授权码code
     * @return
     */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(){
        //授权码存储等处理方式类,使用jdbc,操作oauth_code表
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    /**
     * token的持久化
     * @return
     */
    @Bean
    public TokenStore tokenStore(){
        return new JdbcTokenStore(dataSource);
    }

    /**
     * 自定义token增强链
     * @return
     */
    @Bean
    public TokenEnhancerChain tokenEnhancerChain(){
        TokenEnhancerChain tokenEnhancerChain=new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(new CustomTokenEnhancer(),accessTokenConverter()));
        return tokenEnhancerChain;
    }

    /**
     * jwt token的生成配置
     * @return
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter(){
        JwtAccessTokenConverter converter=new JwtAccessTokenConverter();
        converter.setSigningKey(signingKey);
        return converter;
    }

    /**
     * 配置自定义的granter
     * @param endpointsConfigurer
     * @return
     */
    public TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpointsConfigurer) {
        List<TokenGranter> granters = Arrays.asList(endpointsConfigurer.getTokenGranter());
        return new CompositeTokenGranter(granters);
    }
}
